package com.imageflowpro.image_flow_pro.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.imageflowpro.image_flow_pro.constant.JwtClaimsConstant;
import com.imageflowpro.image_flow_pro.context.BaseContext;
import com.imageflowpro.image_flow_pro.dto.UserListDTO;
import com.imageflowpro.image_flow_pro.dto.WXLoginDTO;
import com.imageflowpro.image_flow_pro.exception.BaseException;
import com.imageflowpro.image_flow_pro.exception.LoginFailedException;
import com.imageflowpro.image_flow_pro.mapper.VerificationCodeMapper;
import com.imageflowpro.image_flow_pro.po.User;
import com.imageflowpro.image_flow_pro.mapper.UserMapper;
import com.imageflowpro.image_flow_pro.po.VerificationCode;
import com.imageflowpro.image_flow_pro.properties.WechatProperties;
import com.imageflowpro.image_flow_pro.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imageflowpro.image_flow_pro.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 统一用户表 服务实现类
 * </p>
 *
 * @author 张家浩
 * @since 2025-05-07
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    static final String WX_ACCESS_TOKEN="https://api.weixin.qq.com/sns/oauth2/access_token";//网页微信登录接口

    static final String WX_LOGIN="https://api.weixin.qq.com/sns/jscode2session";//小程序微信登录接口
    static final String WX_USERINFO="https://api.weixin.qq.com/sns/userinfo";

    static final String WX_GETACCESSTOKEN="https://api.weixin.qq.com/sns/oauth2/access_token";

    @Autowired
    private WechatProperties wechatProperties;

    @Autowired
    private VerificationCodeMapper verificationCodeMapper;


    @Override
    @Transactional
    public User wxLoginUser(WXLoginDTO wxLoginDTO) {
        try {
            WXLoginDTO wxLogin = this.getOpenid(wxLoginDTO.getCode());
            wxLoginDTO.setOpenid(wxLogin.getOpenid());
            //判断openid是否为空，如果为空表示登录失败

            if(wxLogin.getOpenid()==null||StringUtils.isEmpty(wxLogin.getOpenid())){
                throw new LoginFailedException("登录失败,wxLoginDTO:"+ wxLogin.getOpenid()+";"+ wxLogin.getAccessToken());
            }
            User user = this.lambdaQuery()
                    .eq(User::getOpenId, wxLogin.getOpenid())
                    .one();
            if(user!=null){
                return user;
            }
            User loginUser = this.getLoginUser(wxLogin,"CUSTOMER",true);
            if(wxLoginDTO.getHeadimgurl()!=null||wxLoginDTO.getNickname()!=null) {
                loginUser.setHeadimgurl(wxLoginDTO.getHeadimgurl());
                loginUser.setNickname(wxLoginDTO.getNickname());
            }
            this.save(loginUser);
            return loginUser;
        } catch (LoginFailedException e) {
            throw new BaseException("用户微信登录接口出现问题："+e.getMessage());
        }
    }

    @Override
    @Transactional
    public User wxLoginAdmin(WXLoginDTO wxLoginDTO) {
        try {
            WXLoginDTO wxLogin = this.getOpenid(wxLoginDTO.getCode());
            //判断openid是否为空，如果为空表示登录失败
            if(wxLogin.getOpenid()==null||wxLogin.getOpenid().isEmpty()){
                throw new LoginFailedException("登录失败");
            }
            User user = this.lambdaQuery()
                    .eq(User::getOpenId, wxLogin.getOpenid())
                    .one();
            if(user!=null){
                if(user.getRole().equals(JwtClaimsConstant.USER_ROLE)){
                    throw new LoginFailedException("用户不能登录管理员");
                }
                return user;
            }
            boolean super_admin_exists = this.lambdaQuery()
                    .eq(User::getRole, JwtClaimsConstant.SUPER_ADMIN_ROLE)
                    .exists();
            String role="ADMIN";
            if(!super_admin_exists){
                //role="SUPER_ADMIN";
                VerificationCode superVerificationCode = Db.lambdaQuery(VerificationCode.class)
                        .eq(VerificationCode::getCode, wechatProperties.getSecret())
                        .one();
                if(superVerificationCode!=null&&LocalDateTime.now().isBefore(superVerificationCode.getExpireAt())){
                    VerificationCode verificationCode = new VerificationCode();
                    verificationCode.setCode(wechatProperties.getSecret());
                    verificationCode.setType(VerificationCodeServiceImpl.ACTIVATION_CODE_NAME);
                    verificationCode.setExpireAt(LocalDateTime.now().plusYears(1));
                    Db.save(verificationCode);
                }
            }
            User loginUser = this.getLoginUser(wxLogin,role,false);
            if(wxLoginDTO.getHeadimgurl()!=null||wxLoginDTO.getNickname()!=null) {
                loginUser.setHeadimgurl(wxLoginDTO.getHeadimgurl());
                loginUser.setNickname(wxLoginDTO.getNickname());
            }
            this.save(loginUser);
            return loginUser;
        } catch (LoginFailedException e) {
            throw new BaseException("管理员微信登录接口出现问题："+e.getMessage());
        }
    }

    @Override
    @Transactional
    public void verify(String code) {
        try {
            Long id = BaseContext.getCurrentId();
            User user = this.lambdaQuery()
                    .eq(User::getId, id)
                    .one();
            if(user==null){
                throw new LoginFailedException("登录失败");
            }
            if(user.getActive()){
                throw new BaseException("本账号已经激活");
            }
            List<VerificationCode> list = Db.lambdaQuery(VerificationCode.class)
                    .eq(VerificationCode::getCode, code)
                    .eq(VerificationCode::getType,VerificationCodeServiceImpl.ACTIVATION_CODE_NAME)
                    .orderByDesc(VerificationCode::getExpireAt)
                    .list();
            if(list.size()>=2&&LocalDateTime.now().isBefore(list.get(1).getExpireAt())){
                verificationCodeMapper.delete(new LambdaQueryWrapper<VerificationCode>()
                        .eq(VerificationCode::getCode, code)
                        .eq(VerificationCode::getType,VerificationCodeServiceImpl.ACTIVATION_CODE_NAME));
                throw new BaseException("出现了两个相同内容和类别，而且都没有过期的验证码，已经全部清除");
            }
            if(!LocalDateTime.now().isBefore(list.get(0).getExpireAt())){
                throw new BaseException("验证码已经过期");
            }
            user.setActive(true);
            //验证码为特殊验证码，特殊数据库里没有超级管理员，则设置当前用户为超级管理员
            if(code.equals(wechatProperties.getSecret())){
                User superAdmin = this.lambdaQuery()
                        .eq(User::getRole, JwtClaimsConstant.SUPER_ADMIN_ROLE)
                        .one();
                if(superAdmin==null){
                    user.setRole(JwtClaimsConstant.SUPER_ADMIN_ROLE);
                }
            }
            user.setUpdatedAt(LocalDateTime.now());
            this.updateById(user);
            verificationCodeMapper.delete(new LambdaQueryWrapper<VerificationCode>()
                    .eq(VerificationCode::getCode, code)
                    .eq(VerificationCode::getType,VerificationCodeServiceImpl.ACTIVATION_CODE_NAME)
            );
        } catch (LoginFailedException e){
            throw e;
        }
        catch (Exception e) {
            throw new BaseException("账号激活失败："+e.getMessage());
        }
    }

    @Override//根据id更新用户信息
    @Transactional
    public User updatePersonalInformationByIdUser(User user) {
        if(!BaseContext.getCurrentId().equals(user.getId())){
            throw new BaseException("只允许自己修改自己的信息,userId:"+user);
        }
        User getByIdUser = this.lambdaQuery()
                .eq(User::getId, user.getId())
                .one();
        if(getByIdUser==null){
            throw new BaseException("传入用户不存在");
        }
        //此接口不需要修改openid和role的值
        user.setOpenId(null);
        user.setRole(JwtClaimsConstant.USER_ROLE);
        //更新修改时间
        user.setUpdatedAt(LocalDateTime.now());
        this.updateById(user);
        return user;
    }

    @Override
    @Transactional
    public User updatePersonalInformationByIdAdmin(User user) {
        User getByIdUser = this.lambdaQuery()
                .eq(User::getId, user.getId())
                .one();
        if(user.getRole()==null){
            user.setRole(getByIdUser.getRole());
        }
        if(getByIdUser==null){
            throw new BaseException("要修改的用户不存在");
        }
        User loginUser = this.lambdaQuery()
                .eq(User::getId, BaseContext.getCurrentId())
                .one();
        if((!UserServiceImpl.isVerify(getByIdUser.getId()))&&!loginUser.getRole().equals(JwtClaimsConstant.SUPER_ADMIN_ROLE)){
            throw new BaseException("用户未激活");
        }
        if(!(loginUser.getRole().equals(JwtClaimsConstant.SUPER_ADMIN_ROLE)||user.getId().equals(loginUser.getId()))){
            throw new BaseException("只允许超级管理员或者管理员本人修改");
        }
        if(user.getRole().equals(JwtClaimsConstant.SUPER_ADMIN_ROLE)&&!loginUser.getRole().equals(JwtClaimsConstant.SUPER_ADMIN_ROLE)){
            throw new BaseException("只有超级用户可以将自己的超级用户身份转移");
        }
        if(user.getRole().equals(JwtClaimsConstant.SUPER_ADMIN_ROLE)){
            loginUser.setRole(JwtClaimsConstant.ADMIN_ROLE);
            this.updateById(loginUser);
            user.setUpdatedAt(null);
            user.setOpenId(null);
        }
        this.updateById(user);
        return user;
    }

    @Override
    @Transactional
    public UserListDTO adminGetUserList() {
        UserListDTO userListDTO=new UserListDTO();
        User loginUser = this.lambdaQuery()
                .eq(User::getId, BaseContext.getCurrentId())
                .one();
        if(!loginUser.getRole().equals(JwtClaimsConstant.SUPER_ADMIN_ROLE)){
            throw new BaseException("用户不是超级用户");
        }
        List<User> userList = this.lambdaQuery()
                .ne(User::getId, BaseContext.getCurrentId())
                .list();
        userListDTO.setUserList(userList);
        userListDTO.setTotal(userList.size());
        return userListDTO;
    }

    private String getAccessToken(String code){
        Map<String, String> map=new HashMap<>();
        map.put("appid",wechatProperties.getAppid());
        map.put("secret",wechatProperties.getSecret());
        map.put("code", code);
        map.put("grant_type", "authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);
        JSONObject jsonObject = JSON.parseObject(json);
        return jsonObject.getString("access_token");
    }

    //调用微信接口服务，获得当前微信用户的openid
    private WXLoginDTO getOpenid(String code) {
        Map<String, String> map=new HashMap<>();
        map.put("appid",wechatProperties.getAppid());
        map.put("secret",wechatProperties.getSecret());
        map.put("js_code", code);
        map.put("grant_type", wechatProperties.getGrantType());
        //使用工具类发送GET请求
        String json = HttpClientUtil.doGet(WX_LOGIN, map);
        JSONObject jsonObject = JSON.parseObject(json);
        WXLoginDTO wxLoginDTO = new WXLoginDTO();
        wxLoginDTO.setOpenid(jsonObject.getString("openid"));
        wxLoginDTO.setAccessToken(getAccessToken(code));
        return wxLoginDTO;
    }

    private User getLoginUser(WXLoginDTO wxLoginDTO,String role, Boolean active){
        Map<String, String> map=new HashMap<>();
        map.put("openid", wxLoginDTO.getOpenid());
        map.put("access_token", wxLoginDTO.getAccessToken());
        //使用工具类发送GET请求
        String json = HttpClientUtil.doGet(WX_USERINFO, map);
        JSONObject jsonObject = JSON.parseObject(json);
        User user = new User();
        user.setRole(role);
        user.setActive(active);
        user.setOpenId(wxLoginDTO.getOpenid());
        user.setNickname(jsonObject.getString("nickname"));
        user.setHeadimgurl(jsonObject.getString("headimgurl"));
        return user;
    }

    public static boolean isVerify(Long id){
        User user = Db.lambdaQuery(User.class)
                .eq(User::getId, id)
                .one();
        return user.getActive();
    }
}
